#!/usr/bin/python
#
# Copyright 2010 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This code is not supported by Google
#

"""
This script fetches the products submitted (not necessarily published) into 
Merchant Center.

REFERENCE : http://code.google.com/apis/shopping/content/getting-started/usingapi-products.html#Retrieving

USAGE: 
    python fetch_products.py --email=  --passwd=  --cid=

note :
- arguments
  email:  your merchant center email address
  passwd: merchant center login password
  cid: your merchant center ID number
  
- The output is a tab-separated list of productID numbers and when they were 
  last updated the output file is written to "your_mc_id_products.txt" 
  in the current working directory.
"""

import urllib,urllib2
from urllib2 import URLError, HTTPError
import libxml2
import re
import sys
import xml.dom.minidom
import getopt
import logging
import datetime

class fetch_products(object):

  def __init__(self, email, passwd, cid):    
    token = self.getAuthToken(email, passwd)
    self.getProducts(token,cid)

  def getAuthToken(self, email, passwd):
      """ This function returns an authentication token. We use the 
          authentication token to make subsequent 
          fetch requests. We need to do a HTTP POST to get the authentication 
          token.
      """
      #import gdata.client;
      #client = gdata.client.GDClient();
      #client.ClientLogin(email,passwd,"Test","structuredcontent")
      #authToken = client.auth_token.token_string   
            
      authURL = "https://www.google.com/accounts/ClientLogin"
      params = urllib.urlencode({'Email': email, 'Passwd': passwd, 'service': 
                                 'structuredcontent', 'source': 'Test'})
      headers = {"Content-type": "application/x-www-form-urlencoded"}
      req = urllib2.Request(authURL, params, headers)
      try:
        response = urllib2.urlopen(req)
      except HTTPError, e:
          self.log('The server couldnt fulfill the request.', logging.ERROR)
          self.log('Error code: ' + str(e.code), logging.ERROR)
          sys.exit(1)
      except URLError, e:
          self.log('We failed to reach a server.', logging.ERROR)
          self.log( 'Reason: ' + str(e.reason ), logging.ERROR)
          sys.exit(1)
      lresponse = response.read()
      """ Auth response includes several key & value pairs. We just need the 
      pair that starts with Auth= """
      authResponseDict = dict(x.split("=") for x in lresponse.split("\n") if x)
      if authResponseDict["Auth"] is None:
        self.log("Unable to acquire token")
        sys.exit(1)
      authToken = authResponseDict["Auth"] 
      self.log("Acquired Token:" + authToken, logging.INFO)
      return authToken
    
  def getProducts(self, token, cid):
    baseURL = ("https://content.googleapis.com/content/v1/" + cid + 
               "/items/products/generic?max-results=200")
    has_next_link = True;
    
    while (has_next_link):      
      has_next_link = False;
      self.log("Recalling: " + baseURL, logging.INFO) 
      req = urllib2.Request(baseURL)      
      req.add_header("Authorization", "GoogleLogin auth=" + token)
  
      try:
          response = urllib2.urlopen(req)
      except HTTPError, e:
          self.log('The server couldnt fulfill the request.',logging.ERROR)
          self.log('Error code: ' + str(e.code),logging.ERROR)
          sys.exit(1)
      except URLError, e:
          self.log('We failed to reach a server.',logging.ERROR)
          self.log( 'Reason: '+ str(e.reason),logging.ERROR)
          sys.exit(1)
  
      content = response.read()    
      xmldoc = xml.dom.minidom.parseString(content)
  
      doc = libxml2.parseDoc(content)
      ctxt = doc.xpathNewContext()
      ctxt.xpathRegisterNs('openSearch', "http://a9.com/-/spec/opensearchrss/1.0/")
      ctxt.xpathRegisterNs('s', "http://www.google.com/shopping/api/schemas/2010")  
      ctxt.xpathRegisterNs('atom', "http://www.w3.org/2005/Atom")  
      ctxt.xpathRegisterNs('app', "http://www.w3.org/2007/app")
      ctxt.xpathRegisterNs('gd', "http://schemas.google.com/g/2005")
      ctxt.xpathRegisterNs('sc', "http://schemas.google.com/structuredcontent/2009")
      ctxt.xpathRegisterNs('scp', "http://schemas.google.com/structuredcontent/2009/products")
         
      nl_links = ctxt.xpathEval('/atom:feed/atom:link')
      for n_link in nl_links:
         rel = n_link.xpathEval('@rel')[0].content
         if (rel == "next"):
           has_next_link = True;
           baseURL = n_link.xpathEval('@href')[0].content      
                 
      nl_offers = ctxt.xpathEval('/atom:feed/atom:entry')
      for n_offer in nl_offers:
        ctxt.setContextNode(n_offer)
        canonical_id = urllib2.unquote(ctxt.xpathEval('atom:id')[0].content)
        pid = ctxt.xpathEval('sc:id')[0].content
        updated  = ctxt.xpathEval('atom:updated')[0].content
        self.writeToFile(cid,pid + "\t" + updated)
      
      ctxt.xpathFreeContext()  
      doc.freeDoc()
      

      #pp = xmldoc.toprettyxml().encode('utf-8')
      #self.log(pp,logging.INFO)
    
  def log(self,msg, loglevel):
    LOG_FILENAME = 'fetch-products.log'
    logging.basicConfig(filename=LOG_FILENAME,level=logging.INFO)
    m = ('[%s] %s') % (datetime.datetime.now(), msg)
    print m
    if (loglevel == logging.DEBUG):
      logging.debug(m)   
    else:
      logging.info(m)  

  def writeToFile(self,cid,productsXML):
      """ This function takes string input and writes it to a file. """
      try:
        out_file = open(cid + "_products.txt", "a")
        out_file.write(str(productsXML) + '\n')
        out_file.close()
      except IOError:
        print "Unable to save data to file"

if __name__ == '__main__':
  email = None
  passwd = None
  cid = None

  try:
    opts, args = getopt.getopt(sys.argv[1:], None, ["email=","passwd=", "cid="])
  except getopt.GetoptError:
    print 'Please specify --email= --passwd= --cid='
    sys.exit(1)

  for opt, arg in opts:
    if opt == "--email":
      email = arg
    elif opt == "--passwd":
      passwd = arg
    elif opt == "--cid":
      cid = arg      

  if (email is not None  and passwd is not None and cid is not None):
    fetch_products(email,passwd,cid)  
